﻿using System.IO;
using System;
using HtmlAgilityPack;

namespace VS2012_MSHA_Helper
{
    class HtmlParser
    {
        #region 私有字段声明

        private readonly HtmlDocument _htmlDoc;

        private bool _ready;
        #endregion

        #region 私有方法
        //private void Output(string message)
        //{
        //    Trace.WriteLine(message);
        //}

        //private void Output(HtmlNode node)
        //{
        //    Output(node.InnerText);
        //}

        //private HtmlNode GetNextVisiableNode(HtmlNode node)
        //{
        //    var result = node == null ? null : node.NextSibling;
        //    if ((result != null) && (result.NodeType != HtmlNodeType.Element))
        //        result = GetNextVisiableNode(result);
        //    return result;
        //}

        //private string GetSiblingNodeValue(ref HtmlNode node)
        //{
        //    var result = node == null ? null : node.InnerText;
        //    node = GetNextVisiableNode(node);
        //    return result;
        //}

        //public string GetSiblingNodeAtt(ref HtmlNode node)
        //{
        //    var result = node == null ? null : node.Attributes["href"].Value;
        //    node = GetNextVisiableNode(node);
        //    return result;            
        //}

        private HtmlNode SelectSingleNode(HtmlNode parent,string fileter)
        {
            var xpath = "./" + fileter;
            return parent == null ? null : parent.SelectSingleNode(xpath);
        }

        private string GetNodeValue(HtmlNode node)
        {
            return node == null ? null : node.InnerText.TrimStart();
        }

        private string GetNodeAtt(HtmlNode node)
        {
            return  node == null ? null : node.Attributes[ "href" ].Value;
        }

        private string DirectNodeValue(HtmlNode node,string fileter)
        {
            return GetNodeValue(SelectSingleNode(node, fileter));
        }

        private string DirectNodeAtt(HtmlNode node,string fileter)
        {
            return GetNodeAtt(SelectSingleNode(node, fileter));
        }

        private MshaBookGroup ExtractBookGroup(HtmlNode group)
        {
            return new MshaBookGroup
                {
                    Id = DirectNodeValue(group, "span[@class='id']"),
                    Name = DirectNodeValue(group, "span[@class='name']"),
                    Vendor = DirectNodeValue(group, "span[@class='vendor']")
                };
        }

        private MshaBook ExtractBook(HtmlNode book)
        {
            return new MshaBook
                {
                    Id = DirectNodeValue(book, "span[@class='id']"),
                    Locale = DirectNodeValue(book, "span[@class='locale']"),
                    Name = DirectNodeValue(book, "span[@class='name']"),
                    Description = DirectNodeValue(book, "span[@class='description']"),
                    BrandingPackageName = DirectNodeValue(book, "span[@class='BrandingPackageName']")
                };
        }

        private MshaPackage ExtractPackage(HtmlNode package)
        {
            var result = new MshaPackage
                {
                    PackageType = DirectNodeValue(package, "span[@class='packageType']"),
                    PackageFormat = DirectNodeValue(package, "span[@class='packageFormat']"),
                    Name = DirectNodeValue(package, "span[@class='name']"),
                    Deployed = DirectNodeValue(package, "span[@class='deployed']"),
                    LastModified = DirectNodeValue(package, "span[@class='last-modified']"),
                    Etag = DirectNodeValue(package, "span[@class='package-etag']"),
                    CurrentLink = DirectNodeAtt(package, "a[@class='current-link']"),
                    PackageSize = DirectNodeValue(package, "span[@class='package-size-bytes']"),
                    UncompressedSize = DirectNodeValue(package, "span[@class='package-size-bytes-uncompressed']"),
                    ConstituentLink = DirectNodeAtt(package, "a[@class='package-constituent-link']")
                };
            return result;
        }

        #endregion

        #region 构造函数
        public HtmlParser()
        {
            _htmlDoc = new HtmlDocument();
            _ready = false;
        }
        #endregion

        #region 公共方法
        public void LoadFromStream(Stream stream)
        {
            if (stream == null) return;
            try
            {
                _htmlDoc.Load(stream);
                _ready = true;
            }
            catch (Exception e)
            {
                throw new AccessViolationException("Load Stream Error: " + Environment.NewLine + e.Message);
            }
        }

        public void LoadFromFile(string fileName)
        {
            try
            {
                _htmlDoc.Load(fileName);
                _ready = true;
            }
            catch (Exception e)
            {
                throw new FileLoadException("Load File Error: " + Environment.NewLine + e.Message);
            }
        }

        public MshaBookGroups Action()
        {
            if (!_ready)  return null;
            var root = _htmlDoc.DocumentNode;
            if (root == null)
                throw new AccessViolationException("no root node found.");
            var groupList = root.SelectNodes("//div[@class='book-group']");
            if (groupList == null) return null;

            var result = new MshaBookGroups();
            foreach (var bookGroup in groupList)
            {
                var mshaGroup = ExtractBookGroup(bookGroup);
                result.Add(mshaGroup);

                var bookList = bookGroup.SelectNodes("./div[@class='book']");
                if (bookList == null) continue;
                foreach (var book in bookList)
                {
                    var mshaBook = ExtractBook(book);
                    mshaGroup.Add(mshaBook);

                    var packageList = book.SelectNodes("./div[@class='packages']/div");
                    if (packageList == null) continue;
                    foreach (var package in packageList)
                    {
                        var mshaPackage = ExtractPackage(package);
                        mshaBook.Add(mshaPackage);
                    }
                }
            }
            _ready = false;
            return result;
        }
        #endregion

        #region 属性

        #endregion
    }
}
